package com.kmxd.ams.app.archive;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import com.kmxd.ams.client.archive.IArchiveRuleCatalogSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.ArchiveRuleCatalogAddDTO;
import com.kmxd.ams.client.archive.dto.ArchiveRuleCatalogEditDTO;
import com.kmxd.ams.client.archive.dto.ArchiveRuleCatalogQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleCatalogListVO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleCatalogVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeListVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.system.dto.SysConfigAddDTO;
import com.kmxd.ams.core.common.constant.*;
import com.kmxd.ams.core.common.enums.ArchStatusEnum;
import com.kmxd.ams.core.common.enums.CatalogTypeEnum;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.RedisUtils;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveRuleCatalog;
import com.kmxd.ams.infra.archive.mapper.ArchiveRuleCatalogMapper;
import com.kmxd.ams.infra.system.entity.SysConfig;
import com.kmxd.ams.infra.tmpl.util.TmplCommon;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 整理规则-目录树设置 服务实现类
 *
 * @author nickbi
 * @since 2022-07-30
 */
@Service
@AllArgsConstructor
@CacheConfig(cacheNames = CacheConst.CACHE_PREFIX_ARCHIVE_RULE_CATALOG)
public class ArchiveRuleCatalogSvcImpl
    extends ServiceImpl<ArchiveRuleCatalogMapper, ArchiveRuleCatalog>
    implements IArchiveRuleCatalogSvc {

  private ArchiveRuleCatalogMapper archiveRuleCatalogMapper;
  private final TmplCommon tmplCommon;
  private final RedisUtils redisUtils;

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public Page<ArchiveRuleCatalogListVO> selectPage(Page reqPage, ArchiveRuleCatalogQueryDTO req) {
    LambdaQueryWrapper<ArchiveRuleCatalog> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveRuleCatalog>(), req).lambda();
    queryWrapper.orderByAsc(ArchiveRuleCatalog::getSort);
    Page<ArchiveRuleCatalog> page = archiveRuleCatalogMapper.selectPage(reqPage, queryWrapper);
    Page<ArchiveRuleCatalogListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), ArchiveRuleCatalogListVO.class));
    return voPage;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<ArchiveRuleCatalogListVO> selectList(ArchiveRuleCatalogQueryDTO req) {
    LambdaQueryWrapper<ArchiveRuleCatalog> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveRuleCatalog>(), req).lambda();
    queryWrapper.orderByAsc(ArchiveRuleCatalog::getSort);
    List<ArchiveRuleCatalog> list = archiveRuleCatalogMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, ArchiveRuleCatalogListVO.class);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(ArchiveRuleCatalogAddDTO req) {
    ArchiveRuleCatalog entity = BeanUtil.copyProperties(req, ArchiveRuleCatalog.class);
    if (ObjectUtil.isEmpty(req.getPid())) {
      entity.setPid(Constants.DEF_STATUS);
    }
    ArchiveRuleCatalog one =
        getOne(
            Wrappers.<ArchiveRuleCatalog>lambdaQuery()
                .eq(ArchiveRuleCatalog::getStatus, entity.getStatus())
                .eq(ArchiveRuleCatalog::getComId, entity.getComId())
                .eq(ArchiveRuleCatalog::getPid, entity.getPid())
                .eq(ArchiveRuleCatalog::getFondsId, entity.getFondsId())
                .orderByDesc(ArchiveRuleCatalog::getSort)
                .last(" limit 1"));
    if (ObjectUtil.isEmpty(one)) {
      entity.setSort(1);
    } else {
      Integer sort = Optional.ofNullable(one.getSort()).orElse(1);
      entity.setSort(sort + 1);
    }
    entity.setId(IdWorker.getId());
    Integer type = req.getType();
    CatalogTypeEnum typeEnum = CatalogTypeEnum.convert(type);
    switch (typeEnum) {
        // 数据节点
      case CONDITION_NODE:
        // 分组节点
      case GROUP_NODE:
        // 目录节点
      case DIR_NODE:
        archiveRuleCatalogMapper.insert(entity);
        return;
        // 门类节点
      case ARCH_NODE:
        IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
        ArchiveTypeVO archType = archiveTypeSvc.view(req.getArchTypeId());
        if (ObjectUtil.isEmpty(archType)) {
          throw BizTipException.instance(ErrorCode.EXCEPTION, "未知门类");
        }
        entity.setName(archType.getName());
        ArrayList<ImmutableTriple<String, String, Integer>> archCatalogList = Lists.newArrayList();

        AtomicInteger index = new AtomicInteger(1);
        if (BooleanUtil.isTrue(archType.getHaveProject())) {
          archCatalogList.add(
              ImmutableTriple.of(archType.getProjTableId(), "项目", index.getAndIncrement()));
        }
        if (BooleanUtil.isTrue(archType.getHaveVol())) {
          archCatalogList.add(
              ImmutableTriple.of(archType.getVolTableId(), "案卷", index.getAndIncrement()));
        }

        if (BooleanUtil.isTrue(archType.getHaveBox())) {
          archCatalogList.add(
              ImmutableTriple.of(archType.getBoxTableId(), "盒", index.getAndIncrement()));
        }

        archCatalogList.add(
            ImmutableTriple.of(archType.getDocTableId(), "文件", index.getAndIncrement()));

        List<ArchiveRuleCatalog> archModelList =
            archCatalogList.stream()
                .map(
                    item -> {
                      ArchiveRuleCatalog node = new ArchiveRuleCatalog();
                      String tableId = item.getLeft();
                      node.setTableId(tableId);
                      node.setName(item.getMiddle());
                      node.setPid(entity.getId());
                      node.setStatus(entity.getStatus());
                      node.setComId(entity.getComId());
                      node.setFondsId(entity.getFondsId());
                      node.setType(CatalogTypeEnum.ARCH_MODEL_NODE.getCode());
                      node.setArchTypeId(archType.getId());
                      node.setSort(item.getRight());
                      return node;
                    })
                .collect(Collectors.toList());
        archModelList.add(entity);
        saveBatch(archModelList);
    }
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(ArchiveRuleCatalogEditDTO req) {
    ArchiveRuleCatalog entity = BeanUtil.copyProperties(req, ArchiveRuleCatalog.class);
    entity.setComId(SecurityUtil.getCropId());
    entity.setFondsId(SecurityUtil.getFondsId());
    archiveRuleCatalogMapper.updateById(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    this.baseMapper.deleteBatchIds(idList);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public ArchiveRuleCatalogVO view(Long id) {
    ArchiveRuleCatalog entity = archiveRuleCatalogMapper.selectById(id);
    ArchiveRuleCatalogVO vo = BeanUtil.copyProperties(entity, ArchiveRuleCatalogVO.class);
    if (ObjectUtil.isEmpty(vo)) {
      return vo;
    }
    if (ObjectUtil.isNotEmpty(vo.getArchTypeId())) {
      IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
      ArchiveTypeVO view = archiveTypeSvc.view(vo.getArchTypeId());
      vo.setArchTypeName(view.getName());
      vo.setArchInfo(BeanUtil.copyProperties(view, ArchiveTypeListVO.class));
    }
    return vo;
  }

  @CacheEvict(allEntries = true)
  @Override
  public void initArchNode(Long archTypeId) {
    ArchiveRuleCatalogAddDTO dto = new ArchiveRuleCatalogAddDTO();
    IArchiveTypeSvc archiveTypeSvc = SpringUtil.getBean(IArchiveTypeSvc.class);
    ArchiveTypeVO view = archiveTypeSvc.view(archTypeId);
    if (ObjectUtil.isEmpty(view)) {
      log.error("创建门类目录树设置失败，未找到门类信息,门类id:" + archTypeId);
      return;
    }
    dto.setType(CatalogTypeEnum.ARCH_NODE.getCode());
    dto.setArchTypeId(archTypeId);
    dto.setStatus(Constants.CATALOG_DEFAULT_STATUS);
    dto.setComId(view.getComId());
    dto.setFondsId(view.getFondsId());
    add(dto);
    // 收集库
    dto.setStatus(ArchStatusEnum.S0.getCode());
    dto.setId(null);
    add(dto);
    // 归档库
    dto.setStatus(ArchStatusEnum.S1.getCode());
    dto.setId(null);
    add(dto);
    // 前台
    dto.setStatus(Constants.CATALOG_FRONT_STATUS);
    dto.setId(null);
    add(dto);
  }

  /**
   * 获取目录树自定义状态
   *
   * @return
   */
  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public boolean getCustomFlag(Long comId, Long fondsId, Integer status) {
    String key = ConfigConst.CATALOG_CONFIG + ":" + comId + ":" + fondsId + ":" + status;
    SysConfig one = getSysConfig(key);
    boolean flag = false;
    if (ObjectUtil.isNotNull(one)) {
      flag = Boolean.parseBoolean(one.getContent());
    }
    return flag;
  }

  private static SysConfig getSysConfig(String key) {
    ISysConfigSvc configSvc = SpringUtil.getBean(ISysConfigSvc.class);
    return configSvc.getOne(
        Wrappers.<SysConfig>lambdaQuery().eq(SysConfig::getCode, key).last(" limit 1"));
  }

  @CacheEvict(allEntries = true)
  @Override
  public void changeCustomFlag(Long comId, Long fondsId, Integer status, Boolean flag) {
    ISysConfigSvc configSvc = SpringUtil.getBean(ISysConfigSvc.class);
    String key = ConfigConst.CATALOG_CONFIG + ":" + comId + ":" + fondsId + ":" + status;
    SysConfig config = getSysConfig(key);
    if (ObjectUtil.isEmpty(config)) {
      SysConfigAddDTO dto = new SysConfigAddDTO();
      dto.setType(0L);
      dto.setName("目录树自定义配置");
      dto.setCode(key);
      dto.setContent(flag.toString());
      dto.setSort(1);
      dto.setStatus(0);
      configSvc.add(dto);
    } else {
      config.setContent(flag.toString());
      configSvc.updateById(config);
    }
    redisUtils.del(CacheConst.REDIS_PREFIX + key);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void changeSort(String ids) {
    if (CharSequenceUtil.isBlank(ids)) {
      return;
    }
    List<Long> idList = IdUtil.splitSortList(ids);
    List<ArchiveRuleCatalog> list = listByIds(idList);
    if (ObjectUtil.isEmpty(list)) {
      return;
    }
    Ordering<ArchiveRuleCatalog> ordering =
        Ordering.explicit(idList).onResultOf(ArchiveRuleCatalog::getId);
    ImmutableList<ArchiveRuleCatalog> sortList = ordering.immutableSortedCopy(list);
    AtomicInteger index = new AtomicInteger(1);
    sortList.forEach(item -> item.setSort(index.getAndIncrement()));
    updateBatchById(sortList);
  }
}
